/**
 * The layer is the module editor
 *
 * @class dfly.Layer
 * @inherits WireIt.Layer
 * @constructor
 * @param {Obj} config configuration object (see WireIt.Layer)
 */
dfly.Layer = function(config) {
   dfly.Layer.superclass.constructor.call(this, config);
   
   /**
    * Save the path of the module that is being edited
    */
   this.currentlyEditedModule = null;
   
   /**
    * Boolean that prevent modules to execute themselves while we are
    * loading a module or cleaning up the editor
    */
   this.blockExecution = false;
   
   // Adds a click handler on the layer to display the windowAddContainer
   YAHOO.util.Event.addListener(this.el, 'click', this.onClick, this, true);
};

YAHOO.extend(dfly.Layer, WireIt.Layer, {
   
   /**
    * Display the addContainerWindow on click
    */
   onClick: function(e) {
      // Display the addContainerWindow when we click on the layer element OR on a CANVAS
      if(e.target == this.el || (e.target.tagName && e.target.tagName == "CANVAS") ) {
         dfly.addContainerWindow.show(this.onAddNewModule, this, [e.clientX, e.clientY]);
      }
   },
   
   /**
    * Callback called when we want to add a new module in the layer
    */
   onAddNewModule: function(moduleName) {
      try {
         this.addContainer({
            moduleName: moduleName,
            xtype: "dfly.Container",
            position: [Math.max(dfly.addContainerWindow.lastPosition[0]-70,0), Math.max(dfly.addContainerWindow.lastPosition[1]-50,0)]
         });
      }
      catch(ex) {
         console.log("Error while adding container for "+moduleName+" : ", ex.message);
      }
   },
   
   /**
    * Override render to add buttons to the layer
    */
   render: function() {
      dfly.Layer.superclass.render.call(this);
      
      // Buttons :
      var newButton = new YAHOO.widget.Button({ label:"New", id:"dfly-newButton", container:this.el });
      newButton.on("click", this.onNew, this, true);
      
      var loadButton = new YAHOO.widget.Button({ label:"Load", id:"dfly-loadButton", container:this.el });
      loadButton.on("click", this.onLoad, this, true);
      
      var saveButton = new YAHOO.widget.Button({ label:"Save", id:"dfly-saveButton", container:this.el });
      saveButton.on("click", this.onSave, this, true);
      
      var deleteButton = new YAHOO.widget.Button({ label:"Delete", id:"dfly-deleteButton", container:this.el });
      deleteButton.on("click", this.onDelete, this, true);
      
      var helpButton = new YAHOO.widget.Button({ label:"Help", id:"dfly-helpButton", container:this.el });
      helpButton.on("click", this.onHelp, this, true);
      
      this.editingModuleInputName = inputEx.cn('input', {id: 'dfly-editingName', type: 'text', value: '/test/Unamed'});
      this.el.appendChild(this.editingModuleInputName);
   },
   
   /**
    * Create a help panel with an iframe to ./help.htmlx
    */
   onHelp: function() {
      if( !this.helpPanel) {
         this.helpPanel = new YAHOO.widget.Panel('dfly-helpPanel', {
            draggable: true,
            width: '500px',
            visible: false
         });
         this.helpPanel.setBody("<iframe src='help.html' style='width: 100%; border: 0;'/>");
         this.helpPanel.setHeader("You asked for some help ?");
         this.helpPanel.render(document.body);
         this.helpPanel.center();
      }
      this.helpPanel.show();
   },
   
   onNew: function() {
      this.blockExecution = true;
      this.removeAllContainers();
      this.blockExecution = false;
      this.setEditingModule(null);
   },
   
   onDelete: function() {
      var moduleToDelete = this.editingModuleInputName.value;
      var m = dfly.ModuleModel.get(moduleToDelete);
      if(m) {
         m.destroy();
      }
      this.onNew();
      dfly.addContainerWindow.removeModuleFromTree(moduleToDelete);
   },
   
   onSave: function() {
      
      var moduleName = this.editingModuleInputName.value;
      
      var wiring = this.getWiring();
      var parameters = {inputs:[], outputs:[]};
      
      // Generate the "parameters"
      for(var i = 0 ; i < wiring.containers.length ; i++) {
         var c = wiring.containers[i];
         
         if(c.moduleName == moduleName) {
            alert('We cannot run recursive modules (yet...). Please remove modules "'+moduleName+'" before saving.');
            return;
         }
         
         // inputs
         if(c.moduleName == '/system/input') {
            var param = {};
            param.label = c.formValue.name;
            param.type = c.formValue.type.type;
            param.inputParams = {};
            if(c.formValue.type.typeOptions)
            for(var key in c.formValue.type.typeOptions) {
               if(c.formValue.type.typeOptions.hasOwnProperty(key)) {
                  param.inputParams[key] = c.formValue.type.typeOptions[key];
               }
            }
            param.inputParams.name = c.formValue.name;
            parameters.inputs.push(param);
         }
         // outputs
         else if(c.moduleName == '/system/output') {
            var param = {};
            
            param.name = c.formValue.name;
            
            parameters.outputs.push(param);
         }
      }
      
      // Boolean to know if we need to rebuild the module treeView
      var alreadyPresent = !!dfly.ModuleModel.get(moduleName);
      
      if(alreadyPresent) {
         var m = dfly.ModuleModel.get(moduleName);
         m.definition = wiring;//YAHOO.lang.JSON.stringify(wiring);
         m.parameters = parameters;//YAHOO.lang.JSON.stringify(parameters);
         m.save();
      }
      else {
         var newModule = new dfly.ModuleModel( {
            path: moduleName,
            definition: wiring,//YAHOO.lang.JSON.stringify(wiring),
            parameters: parameters//YAHOO.lang.JSON.stringify(parameters)
         });
         newModule.save();
      }
      
      // Regenerate the treeview in the addContainerWindow if this is a new module
      if(!alreadyPresent) {
         dfly.addContainerWindow.refreshModuleList();
      }
   },
   
   onLoad: function() {
      dfly.addContainerWindow.show(this.loadModule,this);
   },
   
   loadModule: function(moduleName) {
      
      this.blockExecution = true;
      
      var m = dfly.ModuleModel.get(moduleName);
      if(m === null) {
         alert("Module not found");
         this.blockExecution = false;
         return;
      }
      
      var def = m.definition;
      
      if(!def) {
         alert("Module '"+moduleName+"' cannot be loaded in the editor.");
         this.blockExecution = false;
         return;
      }
      
      this.removeAllContainers();
      
      this.config.containers = def.containers;
      this.config.wires = def.wires;
      this.initContainers();
      this.initWires();
      
      // Once everything is loaded, we can execute
      this.blockExecution = false;
      
      // Save the module being edited
      this.setEditingModule(moduleName);
   },
   
   // Save the module being edited
   setEditingModule: function(moduleName) {
      this.currentlyEditedModule = moduleName;
      var path = this.currentlyEditedModule;
      if(path == null) {
         path = '/test/Unamed';
      }
      this.editingModuleInputName.value = path;
   },
   
   getWiring: function() {

      var i;
      var obj = {containers: [], wires: []};

      for( i = 0 ; i < this.containers.length ; i++) {
         obj.containers.push( this.containers[i].getConfig() );
      }

      for( i = 0 ; i < this.wires.length ; i++) {
         var wire = this.wires[i];
         
         var termSrc = (wire.terminal1.dflyName.substr(0,6) == "input_") ? wire.terminal2 : wire.terminal1;
         var termTgt = (termSrc == wire.terminal1) ? wire.terminal2 : wire.terminal1;
         
         var wireObj = { 
            src: {moduleId: this.containers.indexOf(termSrc.container), terminalName: termSrc.dflyName}, 
            tgt: {moduleId: this.containers.indexOf(termTgt.container), terminalName: termTgt.dflyName} 
         };
         obj.wires.push(wireObj);
      }

      return obj;
   },
   
   addWire: function(wireConfig) {
      var type = eval(wireConfig.xtype || "WireIt.Wire");

      var src = wireConfig.src;
      var tgt = wireConfig.tgt;
      
      var srcContainer = this.containers[src.moduleId];
      var tgtContainer = this.containers[tgt.moduleId];
      
      var terminal1 = srcContainer.findTerminalByName(src.terminalName);
      var terminal2 = tgtContainer.findTerminalByName(tgt.terminalName);

      var wire = new type( terminal1, terminal2, this.el);
      wire.redraw();

      return wire;
   }
   
});
